using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Xml;
using My.IdlConverter.Util;
using My.IdlConverter.Core.Rules;
using My.IdlConverter.Core.Config;

namespace My.IdlConverter.Sdkmachine.Config
{
    public sealed class SdkmachineConfig
    {
        public static string ConfigFile = "./configuration/sdk/SdkEnvironment.config";

        private XmlDocument cfgDocument = new XmlDocument();
        private StringCollection publicFilePaths = new StringCollection();
        private IDictionary<string, StringCollection> libPaths = new Dictionary<string, StringCollection>();

        private string template = "2005";
        private string version = "MyInside";

        public SdkmachineConfig(string template,string version)
        {
            cfgDocument.Load(ConfigFile);
            this.template = template;
            this.version = version;
        }

        public SdkmachineConfig()
        {
            cfgDocument.Load(ConfigFile);
            this.template = cfgDocument.SelectSingleNode("//Settings/CurrentTemplate").InnerText.Trim();
            this.version = cfgDocument.SelectSingleNode("//Settings/CurrentVersion").InnerText.Trim();
        }

        public static string[] GetTemplateNames()
        {
            XmlDocument document = new XmlDocument();
            document.Load(ConfigFile);

            XmlNodeList templateNodes = document.SelectNodes("//Settings/Setting");
            string[] templateNames = new string[templateNodes.Count];
            for (int i = 0; i < templateNodes.Count; ++i)
            {
                templateNames[i] = templateNodes[i].Attributes["template"].InnerText;
            }

            return templateNames;
        }

        #region config properties
        public string CurrentTemplate
        {
            get
            {
                return template;
            }
        }

        public string CurrentVersion
        {
            get
            {
                return version;
            }
        }
        /// <summary>
        /// Get the  relative path of lib files ,which categoried by "Debug" and "Release"
        /// </summary>
        public IDictionary<string, StringCollection> LibPaths
        {
            get
            {
                libPaths.Clear();

                StringCollection debugLibPaths = AddLibPath(SelectNode("LibPath/Debug"));
                StringCollection releaseLibPaths = AddLibPath(SelectNode("LibPath/Release"));

                libPaths = new Dictionary<string, StringCollection>();
                libPaths.Add(new KeyValuePair<string, StringCollection>("Debug", debugLibPaths));
                libPaths.Add(new KeyValuePair<string, StringCollection>("Release", releaseLibPaths));

                return libPaths;
            }
        }

        /// <summary>
        /// Get the  relative path of public and vos file
        /// </summary>
        public StringCollection PublicFilePaths
        {
            get
            {
                publicFilePaths.Clear();

                XmlNode node = SelectNode("PublicFilePath");
                string[] filePaths = node.InnerText.Split(new char[] { ';' });
                foreach (string nextFile in filePaths)
                {
                    string tmp = nextFile.Trim();
                    if (tmp.Length > 0)
                    {
                        publicFilePaths.Add(tmp);
                    }
                }

                return publicFilePaths;
            }
        }

        private IEnumerable<string> FilterFiles(string elementPath,IEnumerable<string> originFiles)
        {
            IEnumerable<string> ruleTarget = originFiles;

            XmlNode node = SelectNode(elementPath);
            XmlAttribute rulePathAttr = node.Attributes["RulePath"];
            XmlAttribute ruleNameAttr = node.Attributes["RuleName"];
            if ((rulePathAttr == null) || (ruleNameAttr == null))
                return ruleTarget;

            string rulePath = rulePathAttr.InnerText;
            if (System.IO.Path.IsPathRooted(rulePath) == false)
                rulePath = PathUtil.ResolveRelativePath(Environment.CurrentDirectory, rulePath.Trim());

            XmlDocument ruleXml = new XmlDocument();
            ruleXml.Load(rulePath);
            XmlNodeList ruleNodeList = ruleXml.SelectNodes(String.Format("//Rules/Rule[@Name='{0}']", ruleNameAttr.InnerText.Trim()));
            if (ruleNodeList == null)
                return ruleTarget;

            foreach (XmlNode ruleNode in ruleNodeList)
            {
                string[] conditions = ruleNode.Attributes["Condition"].InnerText.Trim().Split(new char[] { ';' });
                Type ruleType = ReflectHelper.ClassForName(ruleNode.Attributes["Type"].InnerText);
                IRule rule = Activator.CreateInstance(ruleType) as IRule;

                System.Diagnostics.Debug.Assert(rule != null);
                ruleTarget = rule.DoIt<string, string>(ruleTarget, conditions);
            }

            return ruleTarget;
        }

        public IEnumerable<string> GetDomFiles(string absoluteDomPath,string sdkVersion)
        {
            string[] allDomFilels = System.IO.Directory.GetFiles(absoluteDomPath, "*.*", System.IO.SearchOption.AllDirectories);
            
            string domPathXmlPath = String.Format("/DomPath[@Version='{0}']", sdkVersion);
            IEnumerable<String> yieldDomFiles = FilterFiles(domPathXmlPath,allDomFilels);

            return yieldDomFiles;
        }

        public IEnumerable<string> GetDomFiles(string absoluteDomPath)
        {
            return GetDomFiles(absoluteDomPath,CurrentVersion);
        }
        /// <summary>
        /// Get the  folder path of dom
        /// </summary>
        public string DomPath
        {
            get
            {
                XmlNode node = SelectNode("/DomPath");
                return node.InnerText.Trim();
            }
            set
            {
                XmlNode node = SelectNode("/DomPath");
                node.InnerText = value;
            }
        }

        /// <summary>
        /// Get the absolute path of the target SDK
        /// Such as D:\IdlConverterSDK\version1.0
        /// </summary>
        public string TargetPath
        {
            get
            {
                XmlNode node = SelectNode("/TargetPath");
                return node.InnerText.Trim();
            }
            set
            {
                XmlNode node = SelectNode("/TargetPath");
                node.InnerText = value;
            }
        }
        #endregion

        #region behavior
        public void Save()
        {
            cfgDocument.SelectSingleNode("//Settings/CurrentTemplate").InnerText = ((template.Length > 0) ? template : "2005");
            cfgDocument.SelectSingleNode("//Settings/CurrentVersion").InnerText = ((version.Length > 0) ? version : "2005");
            cfgDocument.Save(ConfigFile);
        }
        #endregion

        private StringCollection AddLibPath(XmlNode node)
        {
            StringCollection libPaths = new StringCollection();
            string[] allPaths = node.InnerText.Split(new char[] { ';' });
            foreach (string nextPath in allPaths)
            {
                string temp = nextPath.Trim();
                if (temp.Length != 0)
                {
                    libPaths.Add(temp);
                }
            }

            return libPaths;
        }

        private XmlNode SelectNode(string nodeName)
        {
            XmlNode node = cfgDocument.SelectSingleNode(String.Format("//Settings/Setting[@template='{0}']/{1}", template, nodeName));

            return node;
        }
    }
}
